/* 
        module：数据交互模块 WebScoket
*/

/**
 * @class 发送请求或接收实时数据
 * @description 通过 WebScoket 与服务器实时交互，
 * @param {String} url - 与服务器交互的地址
 * @param {any} heartbeatData - 与服务器保持连接的心跳消息
 * @param {Number} timeout - 与服务器心跳的时间间隔
 * @return {function,function,function} 发送消息，接收消息，断开连接
 * @example
 *   new class(url)
 */

class Scoket {
    readonly url: any;
    webSocket: null | WebSocket;
    rec: null;
    isConnect: boolean;
    reConnectNum: number;
    heartCheck: {
        heartbeatData: any; //心跳包
        timeout: any; //每段时间发送一次心跳包 这里设置为60s
        heartbeat: any; //延时发送消息对象（启动心跳新建这个对象，收到消息后重置对象）
        start: (that: any) => void;
        reset: (that: any) => void;
        clear: () => void;
    };
    heartbeatData: string;
    timeout: number;
    onDataReceived!: ((jsonObject: any) => void) | null;
    constructor(url: any, heartbeatData: string, timeout: number | undefined) {
        this.onDataReceived = null;
        this.url = url;
        this.heartbeatData = heartbeatData || '我在连接中，别断';
        this.timeout = timeout || 5 * 1000;
        this.webSocket = null;
        this.rec = null; //断线重连后，延迟5秒重新创建WebSocket连接  rec用来存储延迟请求的代码
        this.isConnect = false; //连接标识 避免重复连接
        this.reConnectNum = 0; //重连次数
        this.heartCheck = {
            heartbeatData: this.heartbeatData, //心跳包
            timeout: this.timeout, //每段时间发送一次心跳包 这里设置为60s
            heartbeat: null, //延时发送消息对象（启动心跳新建这个对象，收到消息后重置对象）
            start: function (that) {
                //开始
                that.heartbeat = setInterval(() => {
                    if (that.isConnect) {
                        that.webSocketSend(this.heartbeatData);
                    } else {
                        that.heartCheck.clear();
                    }
                }, that.timeout);
            },
            reset: function (that) {
                //重置
                clearInterval(this.heartbeat);
                this.start(that);
            },
            clear: function () {
                //清除
                clearInterval(this.heartbeat);
            }
        };
        this.#connect();
    }
    //连接服务
    #connect() {
        if (this.isConnect) {
            console.warn('已经是连接状态了');
            return;
        }
        if ('WebSocket' in window) {
            this.webSocket = new WebSocket(this.url); //创建socket对象
        } else {
            throw new Error('该浏览器不支持websocket!');
        }
        //打开
        this.webSocket.onopen = () => {
            this.webSocketOpen();
        };
        //收信
        this.webSocket.onmessage = (e: { data: any }) => {
            this.webSocketOnMessage(e); // 调用回调函数处理接收到的数据
        };
        //关闭
        this.webSocket.onclose = (e: any) => {
            this.webSocketOnClose(e);
        };
        //连接发生错误的回调方法
        this.webSocket.onerror = (e: any) => {
            this.webSocketonError(e);
        };
    }
    private webSocketOpen() {
        console.log('WebSocket连接成功');
        //首次握手
        this.isConnect = true;
        this.heartCheck.start(this);
        this.reConnectNum = 0;
    }
    private webSocketOnClose(e: string) {
        this.heartCheck.clear();
        this.isConnect = false; //断开后修改标识
        console.warn('webSocket 断开连接');
        //被动断开，重新连接
        if (!e) return;
        if (this.reConnectNum < 3) {
            this.#connect();
            ++this.reConnectNum;
        } else {
            console.warn('连接4次了，还是连不上需要联系管理员');
        }
    }
    private webSocketonError(e: any) {
        this.heartCheck.clear();
        this.isConnect = false; //断开后修改标识
        console.log('WebSocket连接发生错误:', e);
    }
    webSocketSend(data: any) {
        this.webSocket?.send(JSON.stringify(data)); //在这里根据自己的需要转换数据格式
    }
    webSocketOnMessage(e: { data: any }) {
        this.onDataReceived && this.onDataReceived(JSON.parse(JSON.parse(e.data)));
    }
    closeWebSocket() {
        //关闭服务
        this.webSocket && this.webSocket.close();
    }
}
export default Scoket;
